import os
import json
from PIL import Image,ImageOps
from pathlib import Path  
from functools import wraps

def error_disp(func):
    '''错误处理'''
    def wrapper(*args, **kwargs):
        try:
            return func(*args, **kwargs)
        except: pass
    return wrapper

def read_config(config_path):
    '''读取配置文件'''
    def decorator(func):  
        @wraps(func)  
        def wrapper(*args, **kwargs):  
            with open(config_path, 'r') as config_file:  
                config = json.load(config_file)  
                config_cont = (int(config['res_width']), int(config['res_height']), config['background_color'])  
            return func(*args, **kwargs, config=config_cont)  # 添加config作为参数  
        return wrapper  
    return decorator  

@read_config('config.json')
def img_xbm_fun(img_path:str,save_path:str,config):
    '''将图片转换为灰度图并生成xbm文件
    参数1:img_path 图片路径
    参数2:save_path 保存路径
    '''
    resolution,background_color = (config[0],config[1]),config[2]
    img = Image.open(img_path)       # 打开一张图片
    if img_path.endswith(".bmp"):    # 自带方法获取后缀
        bmp_image = img.convert('1')  # 将图像转换为1位模式（黑白）
        gray_img = bmp_image.resize(resolution)   # 调节分辨率 为resolution
        if background_color=="black":
            gray_img = ImageOps.invert(gray_img)  # 图片反色
        gray_img.save(f'{save_path}')        # 将图像保存为XBM格式 
    elif img_path.endswith(".png"):
        gray_img = img.convert("L")      # 将图片转换为灰度图
        gray_img = gray_img.resize(resolution)  # 调节分辨率 128*160
        # 创建一个新的二值图像，模式为'1'  
        binary_image = Image.new('1', (gray_img.size[0], gray_img.size[1]))  
        # 创建一个像素访问对象  
        pixels = binary_image.load()  
        for x in range(0,gray_img.size[0],2):                           #遍历图片的x坐标
            for y in range(0,gray_img.size[1],2):                       #遍历图片的y坐标
                if x+1<gray_img.size[0] and y+1<gray_img.size[1]:
                    get_pixel1 = gray_img.getpixel((x,y))               #获取灰阶等级 0-255
                    get_pixel2 = gray_img.getpixel((x+1,y))             #获取灰阶等级 0-255
                    get_pixel3 = gray_img.getpixel((x,y+1))             #获取灰阶等级 0-255
                    get_pixel4 = gray_img.getpixel((x+1,y+1))           #获取灰阶等级 0-255
                    pixe_list = [get_pixel1,get_pixel2,get_pixel3,get_pixel4]
                    gray_avg = int((sum(pixe_list)/(4))/51)             #计算出4个像素的平均灰度值
                    # gray_avg = 3
                    if background_color == "while":
                        if gray_avg == 0:
                            pixels[x,y]     = 0
                            pixels[x+1,y]   = 0
                            pixels[x,y+1]   = 0
                            pixels[x+1,y+1] = 0
                        elif gray_avg == 1:
                            pixels[x,y]    = 0
                            pixels[x+1,y]  = 0
                            pixels[x,y+1]  = 1
                            pixels[x+1,y+1]= 0
                        elif gray_avg == 2:
                            pixels[x,y]     = 0
                            pixels[x+1,y]   = 1
                            pixels[x,y+1]   = 1
                            pixels[x+1,y+1] = 0
                        elif gray_avg == 3:
                            pixels[x,y]     = 0
                            pixels[x+1,y]   = 1
                            pixels[x,y+1]   = 1
                            pixels[x+1,y+1] = 1
                        else:
                            pixels[x,y]     = 1
                            pixels[x+1,y]   = 1
                            pixels[x,y+1]   = 1
                            pixels[x+1,y+1] = 1
                    else:
                        if gray_avg == 0:
                            pixels[x,y]     = 1
                            pixels[x+1,y]   = 1
                            pixels[x,y+1]   = 1
                            pixels[x+1,y+1] = 1
                        elif gray_avg == 1:
                            pixels[x,y]    = 1
                            pixels[x+1,y]  = 1
                            pixels[x,y+1]  = 0
                            pixels[x+1,y+1]= 1
                        elif gray_avg == 2:
                            pixels[x,y]     = 1
                            pixels[x+1,y]   = 0
                            pixels[x,y+1]   = 0
                            pixels[x+1,y+1] = 1
                        elif gray_avg == 3:
                            pixels[x,y]     = 1
                            pixels[x+1,y]   = 0
                            pixels[x,y+1]   = 0
                            pixels[x+1,y+1] = 0
                        else:
                            pixels[x,y]     = 0
                            pixels[x+1,y]   = 0
                            pixels[x,y+1]   = 0
                            pixels[x+1,y+1] = 0
        binary_image.save(f'{save_path}')
    else:
        print("不是图片")
        # binary_image.show()             #显示图片

class tool_img:
    '''这是一个进行图片格式转换的类'''
    def __init__(self) -> str:
        '''初始化'''
        pass
    # @error_disp
    def img_xbm(self,img_path:Path,save_xbm:Path):
        '''图片转xbm格式 单个转换
        参数1:需要转换的图片路径
        参数2:保存xbm图像的位置
        参数3:resolution 分辨率'''
        if img_path.is_file():
            img_xbm_fun(str(img_path),str(save_xbm))
            print(str(img_path))
        else:
            print("不是文件")
        return 0
    
    # @error_disp  
    async def floder_xbm(self,img_floder:str):
        '''文件夹内图片转xbm格式 批量转换 异步执行
        参数1:需要转换图片所在的文件夹路径'''
        if img_floder == "":
            return -1
        path = Path(img_floder)
        floder_xbm = os.path.join(path,"xbm_img")                          # xbm文件保存的文件夹        
        os.makedirs(floder_xbm,exist_ok=True)                              # 创建文件夹即使存在也不报错
        for file_path in path.rglob("*"):                                  # 遍历所有PIL支持的文件
            # 如果是文件
            if file_path.is_file():
                file_paths = file_path.stem                                # 获取不带扩展的文件名
                self.img_xbm(file_path,os.path.join(floder_xbm,f"{file_paths}.xbm"))
        return 0

    # @error_disp
    def merge_file(self,xbm_file):
        '''将xbm文件内容合并
        参数1 xbm_file xbm所在的文件路径'''
        file_name_suffix = Path(xbm_file)     
        file_name = file_name_suffix.with_suffix("")   # 去掉后缀
        with open(f"{file_name}.h","w+") as h_file:
            h_file.write('#pragma once\n')                                  # 写入.h头文件
            h_file.write("unsigned char im_bits1[] = \n")
            # 生成.h文件的规则
            with open(xbm_file,"r") as xbm_file:
                xbm_content = xbm_file.read()
                xbm_content = xbm_content.replace("#define im_width 64\n", "")  
                xbm_content = xbm_content.replace("#define im_height 64\n", "")
                xbm_content = xbm_content.replace("static char im_bits[] = ","")
                h_file.write(xbm_content)                                   # 写入.h文件  
        return 0   
    
    @error_disp
    def merge_folder(self,xbm_folder):
        '''只能合并gif解包后的文件
        参数1 xbm_folder xbm所在的文件夹'''
        c = 0                           #计数器
        path_folder = Path(xbm_folder).parent                              # 获取上一级文件夹
        arry_name = path_folder.name[:-3].replace('-', '_')                # 数组的名称为文件夹名称
        # path_folder_name = path_folder.name #获取文件夹名字
        # 使用sorted对文件路径进行排序，key参数指定排序的依据  
        sorted_file_paths = sorted(path_folder.rglob('*.xbm'), key=lambda x: int(x.stem))  
        xbm_num = sum(1 for f in Path(xbm_folder).glob('*') if f.is_file())               #文件夹内文件数量

        #计算xbm文件16进制数组的数量
        lista = []
        with open(os.path.join(xbm_folder,"1.xbm"), "r") as f:
            content = f.read()
            lista.append(content)
        arry_num = lista[0].count("0x")

        with open(os.path.join(path_folder,f"arry_{arry_name}.h"),"w+") as h_file:
            #自动生成u8g2调用的规则,直接复制粘贴到特定位置即可
            h_file.write(f'#include "arry_{arry_name}.h"\n')
            h_file.write(f"for (size_t i = 0; i < FRAME_{arry_name}; i++)\n")  
            h_file.write("{\n")  
            h_file.write("      u8g2_ClearBuffer(u8g2); \n")     
            h_file.write(f"     u8g2_DrawXBM(u8g2, x, y, 120, 120, frames_{arry_name}[i]);\n")  
            h_file.write("      u8g2_SendBuffer(u8g2);\n") 
            h_file.write("      if (show_state == 1)\n")
            h_file.write("      {\n")
            h_file.write("          show_state = 0;\n")
            h_file.write("          break;\n")        
            h_file.write("      }\n")
            h_file.write("      vTaskDelay(10 / portTICK_PERIOD_MS);\n") 
            h_file.write("      // frame = (frame + 1) % FRAME_COUNT; \n")
            h_file.write("}\n")
            ##############################################

            #数据写入规则
            h_file.write('#pragma once\n')# 写入.h头文件
            h_file.write(f'#define FRAME_{arry_name} (sizeof(frames_{arry_name}) / sizeof(frames_{arry_name}[0]))\n')
            h_file.write(f"unsigned char frames_{arry_name}[{xbm_num}][{arry_num}] = ")
            h_file.write("{\n")
            for file_path in sorted_file_paths:
                c+=1  
                # 生成.h文件的规则
                with open(file_path,"r") as xbm_file:
                    xbm_content = xbm_file.read()
                    xbm_content = xbm_content.replace("static char im_bits[] = ","")
                    xbm_content = xbm_content.replace("}","},")
                    xbm_content = xbm_content.replace(";","")
                    h_file.write(xbm_content)                # 写入.h文件  
            h_file.write('};\n')# 写入.h头文件
        return path_folder

if __name__ == "__main__":

    app = tool_img()
    app.floder_xbm(r"")

